package com.eraasoftware.npa.server;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class MyServer extends Thread {
	final static int DEFAULT_PORT = 1234;
	static Log log = LogFactory.getLog(MyServer.class);

	private ServerSocketChannel serverChannel;

	/**
	 * Constructs a server bound to the given port.
	 * 
	 * @param port
	 *            the port to bind the server socket.
	 * @throws IOException
	 *             If an I/O error occurs, if the bind operation fails, or if
	 *             the socket is already bound.
	 */
	int port;

	private MyServer(int port) throws IOException {
		this.port = port;

		setDaemon(false);
	}

	public int port() {
		return port;
	}

	@Override
	public void run() {
		log.info("Start server on port " + port);
		try {
			serverChannel = ServerSocketChannel.open();
			serverChannel.socket().bind(new InetSocketAddress(port));
			launchBlockingConcurrent();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/**
	 * Constructs a server bound to the default port.
	 * 
	 * @throws IOException
	 *             If an I/O error occurs, if the bind operation fails, or if
	 *             the socket is already bound.
	 */
	private MyServer() throws IOException {
		this(DEFAULT_PORT);
	}

	/**
	 * Full blocking concurrent version.
	 */
	private void launchBlockingConcurrent() throws IOException {

		while (true) {
			// accept a new client connection
			SocketChannel clientChannel = serverChannel.accept();
			// and serve it in a new thread

			try {
				ServiceListener service = ServiceListenerPoolFactory.newJvmtraService(clientChannel);
				boolean thread = false;
				service.thread(thread);

				Thread t;
				t = new Thread(service);

				t.setName(service.getName());
				t.setDaemon(false);
				t.start();

			} catch (IllegalStateException e) {
				log.error(e, e);
				break;
			} catch (UnsupportedOperationException e) {
				log.error(e, e);
				break;
			} catch (Exception e) {
				log.error(e, e);
				break;
			}

		}
	}

	/**
	 * Main of test.
	 */
	public static void main(String[] args) throws IOException {
		MyServer server;
		if (args.length == 0) {
			server = new MyServer();
		} else {
			server = new MyServer(Integer.parseInt(args[0]));
		}
		server.start();

	}

	static MyServer myServer = null;

	public static MyServer startServer(final Integer port) throws IOException {
		if (myServer == null) {
			int internalPort = port == null ? DEFAULT_PORT : port;
			myServer = new MyServer(internalPort);
			myServer.start();
		}
		return myServer;
	}
}
